/*
 * 
 *
 * Authors: Soeren Gebbert, soeren.gebbert@vti.bund.de
 *          Axel Don, axel.don@vti.bund.de
 *
 * Copyright:
 *
 * Johann Heinrich von Thünen-Institut
 * Institut für Agrarrelevante Klimaforschung
 *
 * Phone: +49 (0)531 596 2601
 *
 * Fax:+49 (0)531 596 2699
 *
 * Mail: ak@vti.bund.de
 *
 * Bundesallee 50
 * 38116 Braunschweig
 * Germany
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "micr_cluster.h"

/* -------------------------------------------------------------------------- */
micr_cluster::micr_cluster() : particle_base() {
    this->x = 0;
    this->y = 0;
    this->z = 0;
    this->mass = 0;
    this->contacts = 0;
}
/* -------------------------------------------------------------------------- */
micr_cluster::micr_cluster(initial_parameters *init_params) : particle_base(init_params) {
    this->x = (float) drand48() * init_params->width;
    this->y = (float) drand48() * init_params->height;
    this->z = (float) drand48() * init_params->max_micr_depth;
    this->mass = init_params->max_initial_micr_mass;
    this->contacts = 0;
}
/* -------------------------------------------------------------------------- */
micr_cluster::micr_cluster(float x, float y, float z, float mass, initial_parameters *init_params) : particle_base(init_params) {
    this->x = x;
    this->y = y;
    this->z = z;
    this->mass = mass;
    this->contacts = 0;
}
/* -------------------------------------------------------------------------- */
void micr_cluster::respirate() {
    this->mass -= this->mass * this->run_params->respiration_rate;
}
/* -------------------------------------------------------------------------- */
void micr_cluster::eat(float mass) {
    this->mass += mass;
    this->contacts++;
}
/* -------------------------------------------------------------------------- */
float micr_cluster::get_radius() {
    // This was the old and empirical way to compute the radius of a cluster
    // in a two dimensional modeling approach
    //double radius = pow(this->mass, 1.0 / 4.0);
    // The porosity is used to adjust the occupied soil volume and therefore the radius
    // This radius computation is based on the microorganism density of 1g/cm^3
    // and the computation of a sphere radius and devided by the pore volume
    
    if(this->init_params->constant_radius)
        return this->run_params->radius;
    
    /* The mass doubles, since the crabon part of the dry mass is 50%.
     * This leads to the conclusion, that when a microorganism consumes 1g of carbon,
     * another 1g of additional mass is consumed.
     */
    double radius = pow(3.0*(this->mass)/this->init_params->porosity/4.0/3.1415926535, 1.0 / 3.0);
    if (radius < this->run_params->radius)
        radius = this->run_params->radius;
    return radius;
}
/* -------------------------------------------------------------------------- */
bool micr_cluster::is_particle_in_radius(carb_particle *cp, float radius) {
    if (cp->get_x() < (this->x - radius))
        return false;
    if (cp->get_x() > (this->x + radius))
        return false;
    if (cp->get_y() < (this->y - radius))
        return false;
    if (cp->get_y() > (this->y + radius))
        return false;
    if (cp->get_z() > (this->z + radius))
        return false;
    if (cp->get_z() < (this->z - radius))
        return false;

    return true;
}
/* -------------------------------------------------------------------------- */
void micr_cluster::move() {

    float width = this->init_params->width;
    float height = this->init_params->height;
    float depth = this->init_params->depth;
    float dx = this->run_params->dxmicr;
    float dy = this->run_params->dymicr;
    float dz = this->run_params->dzmicr;

    float x = (drand48() - 0.5) * dx;
    float y = (drand48() - 0.5) * dy;
    float z = (drand48() - 0.5) * dz;
    this->x += x;
    this->y += y;
    this->z += z;
    
    /* Boundary conditions */
    if (this->x < 0.0)
        this->x += width; /*swap to other side */
    if (this->x > width)
        this->x -= width; /*swap to other side */
    if (this->y < 0.0)
        this->y += height; /*swap to other side */
    if (this->y > height)
        this->y -= height; /*swap to other side */
    if (this->z > 0.0)
        this->z = -1.0 * this->z; /* Reflect */
    if (this->z < depth)
        this->z += 2 * (fabs(this->z) - fabs(depth)); /* Reflect */
}
